﻿namespace WinnerCMS.Common.Security
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading;

    internal static class LdapEncoder
    {
        private static char[][] distinguishedNameCharacterValues;
        private static char[][] filterCharacterValues;
        private static readonly ReaderWriterLockSlim SyncLock = new ReaderWriterLockSlim();

        private static void AcquireReadLock()
        {
            SyncLock.EnterReadLock();
        }

        private static void AcquireWriteLock()
        {
            SyncLock.EnterWriteLock();
        }

        internal static string DistinguishedNameEncode(string input, bool useInitialCharacterRules, bool useFinalCharacterRule)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            if (distinguishedNameCharacterValues == null)
            {
                InitialiseDistinguishedNameSafeList();
            }
            byte[] bytes = Encoding.UTF8.GetBytes(input.ToCharArray());
            char[] chArray = new char[bytes.Length * 3];
            int length = 0;
            AcquireReadLock();
            try
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    byte index = bytes[i];
                    if (((i == 0) && (index == 0x20)) && useInitialCharacterRules)
                    {
                        chArray[length++] = '\\';
                        chArray[length++] = ' ';
                    }
                    else if (((i == 0) && (index == 0x23)) && useInitialCharacterRules)
                    {
                        chArray[length++] = '\\';
                        chArray[length++] = '#';
                    }
                    else if (((i == (bytes.Length - 1)) && (index == 0x20)) && useFinalCharacterRule)
                    {
                        chArray[length++] = '\\';
                        chArray[length++] = ' ';
                    }
                    else if (distinguishedNameCharacterValues[index] != null)
                    {
                        char[] chArray2 = distinguishedNameCharacterValues[index];
                        for (int j = 0; j < chArray2.Length; j++)
                        {
                            chArray[length++] = chArray2[j];
                        }
                    }
                    else
                    {
                        chArray[length++] = (char) index;
                    }
                }
            }
            finally
            {
                ReleaseReadLock();
            }
            return new string(chArray, 0, length);
        }

        private static IEnumerable DistinguishedNameSafeList()
        {
            for (int i = 0x20; i <= 0x7e; i++)
            {
                if (((((i != 0x2c) && (i != 0x2b)) && ((i != 0x22) && (i != 0x5c))) && (((i != 60) && (i != 0x3e)) && ((i != 0x26) && (i != 0x21)))) && ((((i != 0x7c) && (i != 0x3d)) && ((i != 0x2d) && (i != 0x27))) && (i != 0x3b)))
                {
                    yield return i;
                }
            }
        }

        private static void EscapeDistinguisedNameCharacter(char c)
        {
            distinguishedNameCharacterValues[c] = new char[] { '\\', c };
        }

        internal static string FilterEncode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            if (filterCharacterValues == null)
            {
                InitialiseFilterSafeList();
            }
            byte[] bytes = Encoding.UTF8.GetBytes(input.ToCharArray());
            char[] chArray = new char[bytes.Length * 3];
            int length = 0;
            AcquireReadLock();
            try
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    byte index = bytes[i];
                    if (filterCharacterValues[index] != null)
                    {
                        char[] chArray2 = filterCharacterValues[index];
                        for (int j = 0; j < chArray2.Length; j++)
                        {
                            chArray[length++] = chArray2[j];
                        }
                    }
                    else
                    {
                        chArray[length++] = (char) index;
                    }
                }
            }
            finally
            {
                ReleaseReadLock();
            }
            return new string(chArray, 0, length);
        }

        private static IEnumerable FilterEncodingSafeList()
        {
            for (int i = 0x20; i <= 0x7e; i++)
            {
                if ((((i != 40) && (i != 0x29)) && ((i != 0x2a) && (i != 0x2f))) && (i != 0x5c))
                {
                    yield return i;
                }
            }
        }

        private static void InitialiseDistinguishedNameSafeList()
        {
            AcquireWriteLock();
            try
            {
                if (distinguishedNameCharacterValues == null)
                {
                    distinguishedNameCharacterValues = SafeList.Generate(0xff, new SafeList.GenerateSafeValue(SafeList.HashThenHexValueGenerator));
                    SafeList.PunchSafeList(ref distinguishedNameCharacterValues, DistinguishedNameSafeList());
                    EscapeDistinguisedNameCharacter(',');
                    EscapeDistinguisedNameCharacter('+');
                    EscapeDistinguisedNameCharacter('"');
                    EscapeDistinguisedNameCharacter('\\');
                    EscapeDistinguisedNameCharacter('<');
                    EscapeDistinguisedNameCharacter('>');
                    EscapeDistinguisedNameCharacter(';');
                }
            }
            finally
            {
                ReleaseWriteLock();
            }
        }

        private static void InitialiseFilterSafeList()
        {
            AcquireWriteLock();
            try
            {
                if (filterCharacterValues == null)
                {
                    filterCharacterValues = SafeList.Generate(0xff, new SafeList.GenerateSafeValue(SafeList.SlashThenHexValueGenerator));
                    SafeList.PunchSafeList(ref filterCharacterValues, FilterEncodingSafeList());
                }
            }
            finally
            {
                ReleaseWriteLock();
            }
        }

        private static void ReleaseReadLock()
        {
            SyncLock.ExitReadLock();
        }

        private static void ReleaseWriteLock()
        {
            SyncLock.ExitWriteLock();
        }


    }
}

